/*! ******************************************************************************
 *
 * Created on 2021年9月25日
 *
 * Copyright(c) YuZhou Big Data Laboratory CO.,Ltd, 2022.  All rights reserved.
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.yzbdl.lanius.core.plugins.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.pentaho.di.core.plugins.PluginTypeInterface;
import org.yzbdl.lanius.core.event.EventContext;
import org.yzbdl.lanius.core.exception.LaniusEngineDbException;
import org.yzbdl.lanius.core.metastore.DbCookies;
import org.yzbdl.lanius.core.plugins.event.ClassificationAddEvent;
import org.yzbdl.lanius.core.plugins.event.ClassificationDeleteEvent;
import org.yzbdl.lanius.core.plugins.event.ClassificationModifyEvent;
import org.yzbdl.lanius.core.plugins.metastore.*;

import com.google.common.collect.Maps;

import cn.hutool.db.Entity;

/**
 * 插件类别数据业务
 *
 * @author hs@yzbdl.ac.cn
 * @version 1.0
 * @date 2019-06-11 10:40
 */
public class ClassificationService {

    private static ClassificationService classificationService = new ClassificationService();

    private LdrClassificationDao ldrClassificationDao = LdrClassificationDao.getInstance();

    private LdrCategoryDao ldrCategoryDao = LdrCategoryDao.getInstance();

//    private LdrPluginClassificationDao ldrPluginClassificationDao = new LdrPluginClassificationDao();

    private ClassificationService() {}

    public static ClassificationService getInstance() {
        return classificationService;
    }

    // =====================================================================================================================
    // add start
    // =====================================================================================================================

    /**
     * 添加 自定义 ClassificationEntity
     *
     * @param name
     * @param pluginTypeClass
     */
    public void addCustomize(String name, Class<? extends PluginTypeInterface> pluginTypeClass) {
        try {
            if (StringUtils.isEmpty(name))
                return;
            LdrClassificationEntity entity = new LdrClassificationEntity();
            entity.setName(name);
            // entity.setFuncType(funcType);
            entity.setPluginTypeClass(pluginTypeClass.getName());
            entity.setLogicType(LogicType.CUSTOMIZE.getId());
            Integer sortNum = ldrClassificationDao.getCustomizeMaxSortNum(pluginTypeClass.getName());
            sortNum = (sortNum == null ? 0 : sortNum);
            entity.setSortNum(sortNum + 1);

            ldrClassificationDao.save(entity);

            EventContext.publish(new ClassificationAddEvent(entity));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加默认栏目
     * <p>
     * 1,如果数据库已经存在, 则直接查询返回 <br/>
     * 2,如果数据库还没有记录, 则先新增再返回.
     * 
     * @return
     * @throws LaniusEngineDbException
     */
    public LdrClassificationEntity addDefault(Class<? extends PluginTypeInterface> pluginType)
        throws LaniusEngineDbException {
        LdrClassificationEntity ldrClassificationEntity =
            ldrClassificationDao.getOne(pluginType.getName(), LogicType.DEFAULT.getId());
        if (ldrClassificationEntity == null) {
            ldrClassificationEntity = new LdrClassificationEntity();
            ldrClassificationEntity.setPluginTypeClass(pluginType.getName());
            ldrClassificationEntity.setLogicType(LogicType.DEFAULT.getId());
            ldrClassificationEntity.setName(LdrClassificationEntity.DEFAULT_NAME);
            ldrClassificationEntity.setSortNum(LdrClassificationEntity.DEFAULT_SORT);
            ldrClassificationDao.save(ldrClassificationEntity);
        }
        return ldrClassificationEntity;
    }

    /**
     * 添加默认栏目
     * <p>
     * 1,如果数据库已经存在, 则直接查询返回 <br/>
     * 2,如果数据库还没有记录, 则先新增再返回.
     * 
     * @return
     * @throws LaniusEngineDbException
     */
    public LdrClassificationEntity addDefault(String pluginType) throws LaniusEngineDbException {
        LdrClassificationEntity ldrClassificationEntity =
            ldrClassificationDao.getOne(pluginType, LogicType.DEFAULT.getId());
        if (ldrClassificationEntity == null) {
            ldrClassificationEntity = new LdrClassificationEntity();
            ldrClassificationEntity.setPluginTypeClass(pluginType);
            ldrClassificationEntity.setLogicType(LogicType.DEFAULT.getId());
            ldrClassificationEntity.setName(LdrClassificationEntity.DEFAULT_NAME);
            ldrClassificationEntity.setSortNum(LdrClassificationEntity.DEFAULT_SORT);
            ldrClassificationDao.save(ldrClassificationEntity);
        }
        return ldrClassificationEntity;
    }

    /**
     * 添加常用栏目
     * <p>
     * 1,如果数据库已经存在, 则直接查询返回 <br/>
     * 2,如果数据库还没有记录, 则先新增再返回.
     * 
     * @return
     * 
     * @return
     * @throws LaniusEngineDbException
     */
    public LdrClassificationEntity addCommonly(Class<? extends PluginTypeInterface> pluginType)
        throws LaniusEngineDbException {
        LdrClassificationEntity ldrClassificationEntity =
            ldrClassificationDao.getOne(pluginType.getName(), LogicType.COMMONLY.getId());
        if (ldrClassificationEntity == null) {
            ldrClassificationEntity = new LdrClassificationEntity();
            ldrClassificationEntity.setPluginTypeClass(pluginType.getName());
            ldrClassificationEntity.setLogicType(LogicType.COMMONLY.getId());
            ldrClassificationEntity.setName(LdrClassificationEntity.COMMONLY_NAME);
            ldrClassificationEntity.setSortNum(LdrClassificationEntity.COMMONLY_SORT);
            ldrClassificationDao.save(ldrClassificationEntity);
        }
        return ldrClassificationEntity;
    }

    // /**
    // * 添加云端栏目
    // * <p>
    // * 1,如果数据库已经存在, 则直接查询返回 <br/>
    // * 2,如果数据库还没有记录, 则先新增再返回.
    // *
    // * @return
    // *
    // * @return
    // * @throws LaniusEngineDbException
    // */
    // public ClassificationEntity addMarket(Class<? extends PluginTypeInterface> pluginType)
    // throws LaniusEngineDbException {
    // ClassificationEntity classificationEntity =
    // classificationDao.getOne(pluginType.getName(), LogicType.MARKET.getId());
    // if (classificationEntity == null) {
    // classificationEntity = new ClassificationEntity();
    // classificationEntity.setPluginTypeClass(pluginType.getName());
    // classificationEntity.setLogicType(LogicType.MARKET.getId());
    // classificationEntity.setName(ClassificationEntity.MARKET_NAME);
    // classificationEntity.setSortNum(ClassificationEntity.MARKET_SORT);
    // classificationDao.save(classificationEntity);
    // }
    // return classificationEntity;
    // }

    // =====================================================================================================================
    // add end
    // =====================================================================================================================

    /**
     * 级联查找默认分类
     * 
     * @return
     */
    public LdrClassificationEntity getDefault(Class<? extends PluginTypeInterface> pluginType) {
        LdrClassificationEntity ldrClassificationEntity = null;

        try {
            StringBuffer sql = new StringBuffer("select ");
            sql.append(DbCookies.getFields(LdrClassificationEntity.class, "cl", "cl_"));
            sql.append(", ");
            sql.append(DbCookies.getFields(LdrCategoryEntity.class, "ca", "ca_"));
            sql.append(", ");
            sql.append(DbCookies.getFields(LdrPluginEntity.class, "p", "p_"));
            sql.append(" ");
            sql.append("from ldr_plugin p ");
            sql.append("left join ldr_plugin_category  pc on p.id = pc.plugin_id ");
            sql.append("left join ldr_category ca on pc.category_id = ca.id ");
            sql.append("left join ldr_classification cl on cl.id  = ca.classification_id ");
            sql.append("where p.is_valid = true and cl.id = ");
            sql.append("(select id from ldr_classification c2 where c2.logic_type = " + LogicType.DEFAULT.getId()
                + " and c2.plugin_type_class = '" + pluginType.getName() + "') ");
            sql.append("order by ca.sort_num asc, ca.create_time desc, ca.name asc");

            Map<String, LdrClassificationEntity> tempClassification = Maps.newHashMap();
            Map<String, LdrCategoryEntity> tempCategory = Maps.newHashMap();

            List<Entity> maps = ldrClassificationDao.getEntitysBySql(sql.toString());
            for (Entity map : maps) {
                ldrClassificationEntity = tempClassification.get(map.getStr("cl_id"));
                if (ldrClassificationEntity == null) {
                    ldrClassificationEntity = new LdrClassificationEntity();
                    DbCookies.fillField(map, ldrClassificationEntity, "cl_");
                    tempClassification.put(map.getStr("cl_id"), ldrClassificationEntity);
                }

                LdrCategoryEntity ldrCategoryEntity = tempCategory.get(map.getStr("ca_name"));
                if (ldrCategoryEntity == null) {
                    ldrCategoryEntity = new LdrCategoryEntity();
                    DbCookies.fillField(map, ldrCategoryEntity, "ca_");
                    tempCategory.put(map.getStr("ca_name"), ldrCategoryEntity);
                    ldrClassificationEntity.getCategoryEntities().add(ldrCategoryEntity);
                }

                LdrPluginEntity ldrPluginEntity = new LdrPluginEntity();
                DbCookies.fillField(map, ldrPluginEntity, "p_");

                ldrCategoryEntity.getPluginEntities().add(ldrPluginEntity);
            }

        } catch (LaniusEngineDbException e) {
            e.printStackTrace();
        }
        return ldrClassificationEntity;
    }

    /**
     * 级联查找默认分类根据关键字过滤
     *
     * @return
     */
    public LdrClassificationEntity getDefaultByFilter(Class<? extends PluginTypeInterface> pluginType, String keyName) {
        LdrClassificationEntity ldrClassificationEntity = null;

        try {
            StringBuffer sql = new StringBuffer("select ");
            sql.append(DbCookies.getFields(LdrClassificationEntity.class, "cl", "cl_"));
            sql.append(", ");
            sql.append(DbCookies.getFields(LdrCategoryEntity.class, "ca", "ca_"));
            sql.append(", ");
            sql.append(DbCookies.getFields(LdrPluginEntity.class, "p", "p_"));
            sql.append(" ");
            sql.append("from ldr_plugin p ");
            sql.append("left join ldr_plugin_category  pc on p.id = pc.plugin_id ");
            sql.append("left join ldr_category ca on pc.category_id = ca.id ");
            sql.append("left join ldr_classification cl on cl.id  = ca.classification_id ");
            sql.append("where p.is_valid = true and cl.id = ");
            sql.append("(select id from ldr_classification c2 where c2.logic_type = " + LogicType.DEFAULT.getId()
                + " and c2.plugin_type_class = '" + pluginType.getName() + "') ");
            if (StringUtils.isNotBlank(keyName)) {
                sql.append(" and p.name ilike '%" + keyName + "%'");
            }
            sql.append("order by ca.sort_num asc, ca.create_time desc, ca.name asc");

            Map<String, LdrClassificationEntity> tempClassification = Maps.newHashMap();
            Map<String, LdrCategoryEntity> tempCategory = Maps.newHashMap();

            List<Entity> maps = ldrClassificationDao.getEntitysBySql(sql.toString());
            for (Entity map : maps) {
                ldrClassificationEntity = tempClassification.get(map.getStr("cl_id"));
                if (ldrClassificationEntity == null) {
                    ldrClassificationEntity = new LdrClassificationEntity();
                    DbCookies.fillField(map, ldrClassificationEntity, "cl_");
                    tempClassification.put(map.getStr("cl_id"), ldrClassificationEntity);
                }

                LdrCategoryEntity ldrCategoryEntity = tempCategory.get(map.getStr("ca_name"));
                if (ldrCategoryEntity == null) {
                    ldrCategoryEntity = new LdrCategoryEntity();
                    DbCookies.fillField(map, ldrCategoryEntity, "ca_");
                    tempCategory.put(map.getStr("ca_name"), ldrCategoryEntity);
                    ldrClassificationEntity.getCategoryEntities().add(ldrCategoryEntity);
                }

                LdrPluginEntity ldrPluginEntity = new LdrPluginEntity();
                DbCookies.fillField(map, ldrPluginEntity, "p_");

                ldrCategoryEntity.getPluginEntities().add(ldrPluginEntity);
            }

        } catch (LaniusEngineDbException e) {
            e.printStackTrace();
        }
        return ldrClassificationEntity;
    }

    // /**
    // * 级联查找云端分类
    // *
    // * @return
    // */
    // public ClassificationEntity getMarket(Class<? extends PluginTypeInterface> pluginType) {
    // ClassificationEntity classificationEntity = null;
    //
    // try {
    // StringBuffer sql = new StringBuffer("select ");
    // sql.append("cl.id as CL_ID , cl.plugin_type_class as CL_PLUGINTYPECLASS, cl.logic_type as CL_LOGICTYPE, ");
    // sql.append(
    // "cl.name as CL_NAME, cl.create_time as CL_CREATETIME, cl.sort_num as CL_SORTNUM, cl.expanded as CL_EXPANDED, ");
    //
    // sql.append(
    // "ca.id as CA_ID, ca.name as CA_NAME, ca.plugin_type_class as CA_PLUGINTYPECLASS, ca.expanded as CA_EXPANDED, ");
    // sql.append("ca.create_time as CA_CREATETIME, ca.is_cloud as CA_ISCLOUD, ");
    //
    // sql.append(
    // "p.id as P_ID, p.plugin_id as P_PLUGINID, p.image as P_PLUGINIMAGE, p.plugin_type_name as P_PLUGINTYPECLASS,
    // p.name as P_NAME, ");
    // sql.append("p.profile as P_PROFILE, p.version as P_VERSIONNUMBER, ");
    // sql.append(
    // "p.charge_type as P_CHARGETYPE, p.usage_count as P_USAGECOUNT, p.is_valid as P_ISVALID, p.is_cloud as P_ISCLOUD,
    // p.create_time as P_CREATETIME ");
    //
    // sql.append("from ldr_plugin p ");
    // sql.append("left join ldr_plugin_category pc on p.id = pc.plugin_id ");
    // sql.append("left join ldr_category ca on pc.category_id = ca.id ");
    // sql.append("left join ldr_classification cl on cl.id = ca.classification_id ");
    // sql.append("where p.is_valid = true and cl.id = ");
    // sql.append("(select id from ldr_classification c2 where c2.logic_type = " + LogicType.MARKET.getId()
    // + " and c2.plugin_type_class = '" + pluginType.getName() + "') ");
    // sql.append("order by ca.sort_num asc,ca.create_time desc, ca.name asc");
    //
    // Map<String, ClassificationEntity> tempClassification = Maps.newHashMap();
    // Map<String, CategoryEntity> tempCategory = Maps.newHashMap();
    //
    // List<Entity> maps = classificationDao.getEntitysBySql(sql.toString());
    // for (Entity map : maps) {
    //
    // classificationEntity = tempClassification.get(map.getStr("CL_ID"));
    // if (classificationEntity == null) {
    // classificationEntity = new ClassificationEntity();
    // classificationEntity.setId(map.getInt("CL_ID"));
    // classificationEntity.setName(map.getStr("CL_NAME"));
    // classificationEntity.setPluginTypeClass(map.getStr("CL_PLUGINTYPECLASS"));
    // classificationEntity.setSortNum(map.getInt("CL_SORTNUM"));
    // classificationEntity.setLogicType(map.getInt("CL_LOGICTYPE"));
    // classificationEntity.setExpanded(map.getBool("CL_EXPANDED"));
    // classificationEntity.setCreateTime(map.getDate("CL_CRE ATETIME"));
    // tempClassification.put(map.getStr("CL_ID"), classificationEntity);
    // }
    //
    // CategoryEntity categoryEntity = tempCategory.get(map.getStr("CA_ID"));
    // if (categoryEntity == null) {
    // categoryEntity = new CategoryEntity();
    // categoryEntity.setId(map.getInt("CA_ID"));
    // categoryEntity.setClassificationId(map.getInt("P_ID"));
    // categoryEntity.setName(map.getStr("CA_NAME"));
    // categoryEntity.setPluginTypeClass(map.getStr("CA_PLUGINTYPECLASS"));
    // categoryEntity.setIsCloud(map.getBool("CA_ISCLOUD"));
    // categoryEntity.setExpanded(map.getBool("CA_EXPANDED"));
    // categoryEntity.setCreateTime(map.getDate("CA_CREATETIME"));
    // tempCategory.put(map.getStr("CA_ID"), categoryEntity);
    // classificationEntity.getCategoryEntities().add(categoryEntity);
    // }
    //
    // PluginEntity pluginEntity = new PluginEntity();
    // pluginEntity.setId(map.getInt("P_ID"));
    // pluginEntity.setPluginId(map.getStr("P_PLUGINID"));
    // // pluginEntity.setPluginImage(map.getStr("P_PLUGINIMAGE"));
    // pluginEntity.setImage(map.getStr("P_PLUGINIMAGE"));
    // pluginEntity.setPluginTypeName(map.getStr("P_PLUGINTYPECLASS"));
    // pluginEntity.setName(map.getStr("P_NAME"));
    // // pluginEntity.setFullPath(map.get("P_FULLPATH")));
    // // pluginEntity.setFolderName(map.getStr("P_FOLDERNAME"));
    // pluginEntity.setProfile(map.getStr("P_PROFILE"));
    // // pluginEntity.setVersionId(map.getStr("P_VERSIONID"));
    // // pluginEntity.setVersionNumber(map.getStr("P_VERSIONNUMBER"));
    // pluginEntity.setVersion(map.getStr("P_VERSIONNUMBER"));
    // pluginEntity.setChargeType(map.getInt("P_CHARGETYPE"));
    // pluginEntity.setUsageCount(map.getInt("P_USAGECOUNT"));
    // pluginEntity.setIsValid(map.getBool("P_ISVALID"));
    // pluginEntity.setCreateTime(map.getDate("P_CREATETIME"));
    // categoryEntity.getPluginEntities().add(pluginEntity);
    // }
    //
    // } catch (LaniusEngineDbException e) {
    // e.printStackTrace();
    // }
    // return classificationEntity;
    // }

    /**
     * 获取所有 ClassificationEntity
     *
     * @param pluginType 插件类别类
     * @return
     */
    public List<LdrClassificationEntity> getAll(Class<? extends PluginTypeInterface> pluginType) {
        try {
            return ldrClassificationDao.getAll(pluginType.getName());
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * 查找最新的ClassificationEntity
     *
     * @return
     */
    public List<LdrClassificationEntity> getLeast(Class<? extends PluginTypeInterface> pluginType, LogicType logicType,
        int count) {
        try {
            return ldrClassificationDao.getLeast(pluginType.getName(), logicType.getId(), count);
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * 根据插件类别, 逻辑类别查找
     *
     * @param pluginType 插件类别类
     * @param logicType  逻辑类别, 1:常用, 2:自定义, 3:本地(默认), 4:云端(商店)
     * @return
     */
    public List<LdrClassificationEntity> getAll(Class<? extends PluginTypeInterface> pluginType, LogicType logicType) {
        try {
            return ldrClassificationDao.getAll(pluginType.getName(), logicType.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * 根据插件类别, 逻辑类别查找
     *
     * @param pluginTypeClass 插件类别类全称
     * @param logicType  逻辑类别, 1:常用, 2:自定义, 3:本地(默认), 4:云端(商店)
     * @return
     */
    public List<LdrClassificationEntity> getAll(String pluginTypeClass, LogicType logicType) {
        try {
            return ldrClassificationDao.getAll(pluginTypeClass, logicType.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * @param pluginType
     * @param logicType
     * @return
     * @throws LaniusEngineDbException
     */
    public LdrClassificationEntity getOne(Class<? extends PluginTypeInterface> pluginType, int logicType)
        throws LaniusEngineDbException {
        return ldrClassificationDao.getOne(pluginType.getName(), logicType);
    }

    /**
     * 添加 ClassificationEntity
     *
     * @param entity
     */
    public void update(LdrClassificationEntity entity) {
        try {
            ldrClassificationDao.update(entity);
            EventContext.publish(new ClassificationModifyEvent(entity));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 展开分类
     *
     * @param ids
     */
    public void expandClassification(Integer... ids) {
        try {
            ldrClassificationDao.updateExpandStatus(true, ids);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 收缩分类
     *
     * @param ids
     */
    public void collapseClassification(Integer... ids) {
        try {
            ldrClassificationDao.updateExpandStatus(false, ids);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除 ClassificationEntity
     *
     * @param entity
     */
    public void delete(LdrClassificationEntity entity) {
        try {
            ldrClassificationDao.delete(entity.getId());

//            ldrPluginClassificationDao.deleteByClassificationId(entity.getId());
            ldrCategoryDao.deleteByClassificationId(entity.getId());

            EventContext.publish(new ClassificationDeleteEvent(entity));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
